// eslint-disable-next-line import/named
import { ActionTree } from 'vuex'
import { StateInterface } from './state'
import { cloneDeep, isNumber, isString } from 'lodash'
import { AppWidgetData, defaultWidgetOptions, Widget } from 'src/store/widget/state'
import { compressStrToBase64, decompressBase64ToStr, loadObject, saveObject } from 'assets/utils'
import iUser from 'src/api/user'
import { defaultWorkbenchOptions } from 'src/store/workbench/state'
import { Tool } from 'src/store/tool/state'
import iTool from 'src/api/tool'
import { genWidgetId, LayoutEngine } from 'src/utils/widget'

const actions: ActionTree<StateInterface, StateInterface> = {
  storeSave: async function ({
    state,
    getters,
    commit
  }, gridLayouts: {
    id: string,
    x: number, y: number,
    w: number, h: number,
  }[]) {
    const isSharePanel = !!state.shareId
    if (isSharePanel) return

    if (gridLayouts) {
      const widgets = state.widget.widgets.map((appLayout: Widget) => {
        const gridLayout = gridLayouts.find(e => e.id === appLayout.id)
        return {
          ...appLayout,
          ...gridLayout
        }
      })
      commit('widget/updateWidgets', widgets)
    }
    // 本地存储
    saveObject(getters.storageKey, {
      widgetApps: state.widget.apps,
      widgetWidgets: state.widget.widgets,
      widgetOptions: state.widget.options,
      workbenchOptions: state.workbench.options
    })
    // 云端存储
    if (getters.isLogin) {
      await iUser.saveStorage({
        ...getters.storageQuery,
        data: compressStrToBase64(JSON.stringify({
          apps: state.widget.apps,
          widgets: state.widget.widgets,
          widgetOptions: state.widget.options,
          workbenchOptions: state.workbench.options
        }))
      })
    }
  },

  async storeLoad ({
    getters,
    rootState,
    state,
    dispatch,
    commit
  }) {
    const isSharePanel = !!state.shareId
    const isMainPanel = state.currentWorkbenchId === 'main' && !isSharePanel

    const getWorkbenchStorage = async function () {
      let apps: AppWidgetData[], widgets: Widget[]
      let widgetOptions, workbenchOptions
      let remoteStorage
      // 云端读取
      if (getters.isLogin) {
        remoteStorage = await iUser.loadStorage(getters.storageQuery)
        if (!remoteStorage || !remoteStorage.data) {
          remoteStorage = {
            data: {
              widgetApps: [],
              widgetWidgets: [],
              widgetOptions: {
                float: false,
                initialized: true
              },
              workbenchOptions: defaultWorkbenchOptions()
            }
          }
        }
      }
      if (remoteStorage) {
        if (isString(remoteStorage.data)) {
          remoteStorage.data = JSON.parse(decompressBase64ToStr(remoteStorage.data))
        }
        ({
          apps,
          widgets,
          widgetOptions,
          workbenchOptions
        } = remoteStorage.data)
      } else {
        const workbenchData = loadObject(getters.storageKey) || {}
        apps = workbenchData.widgetApps
        widgets = workbenchData.widgetWidgets
        widgetOptions = workbenchData.widgetOptions
        workbenchOptions = workbenchData.workbenchOptions
      }

      widgetOptions = widgetOptions || { isInitialized: false }
      widgetOptions.isInitialized = isMainPanel ? widgetOptions.isInitialized : true

      // Widgets & Apps
      apps = apps || []
      widgets = widgets || []

      // 更新 APP 数据格式
      apps = apps.map(e => {
        if (!e.clickCount) {
          e.clickCount = 0
        }
        return e
      })
      return {
        apps,
        widgets,
        widgetOptions,
        workbenchOptions
      }
    }

    const getSharePanelStorage = async function (id: string) {
      const storage = await iUser.getSharePanel({}, {
        pathParams: { id }
      })
      commit('setSharePanelInfo', {
        userId: storage.userId,
        userName: storage.userName
      })
      const storageData = JSON.parse(decompressBase64ToStr(storage.data))
      const apps: AppWidgetData[] = storageData.apps
      const widgets: Widget[] = storageData.widgets
      const widgetOptions = storageData.widgetOptions
      const workbenchOptions = storageData.workbenchOptions
      return {
        apps,
        widgets,
        widgetOptions,
        workbenchOptions
      }
    }
    let storage
    if (isSharePanel && state.shareId) {
      storage = await getSharePanelStorage(state.shareId)
    } else {
      storage = await getWorkbenchStorage()
    }
    let apps = storage.apps
    let widgets = storage.widgets
    let widgetOptions = storage.widgetOptions
    let workbenchOptions = storage.workbenchOptions

    // 同步用户新收藏应用 - 加入工作台
    let collectionApps: Tool[] = []
    apps = apps.filter(e => {
      return e.appData && e.appData.name
    })
    if (isMainPanel && rootState.userInfo.toolCollection) {
      collectionApps = await iTool.getToolByIds({
        ids: rootState.userInfo.toolCollection
      })
      commit('widget/setCollectionApps', collectionApps)
    }
    const appendApps = collectionApps.filter(e => !apps.find(v => v.id === e._id))
    const retainWidgetApps = apps.filter(e => e.type === 2 || collectionApps.find(v => v._id !== e.id))

    apps = [
      ...retainWidgetApps,
      ...appendApps.map(e => {
        return {
          id: e._id,
          type: 1,
          appData: e,
          clickCount: 0,
          createdAt: new Date(),
          updatedAt: new Date()
        }
      })
    ].filter(e => {
      return e.appData && e.appData.name
    })

    // Widget Options
    widgetOptions = widgetOptions && Object.keys(widgetOptions).length !== 0
      ? widgetOptions
      : defaultWidgetOptions
    commit('widget/setOptions', widgetOptions)

    // Workbench Options
    workbenchOptions = workbenchOptions && Object.keys(workbenchOptions).length !== 0
      ? workbenchOptions
      : defaultWorkbenchOptions()
    // 仅在主面板下更新工作台配置
    if (isMainPanel || isSharePanel) {
      commit('workbench/setOptions', workbenchOptions)
    } else if (!state.workbench.options.backgroundId) {
      commit('workbench/setOptions', workbenchOptions)
    }
    // 处理 auto play
    if (workbenchOptions.autoPlay) {
      const rand = Math.floor(Math.random() * workbenchOptions.backgrounds.length)
      workbenchOptions.backgroundId = workbenchOptions.backgrounds[rand].id
    }

    // 过滤不符合当前标准类型的 Widget
    const supportTypes = [
      'AppWidget',
      'AppGroupWidget',
      'SearchBarWidget',
      'WeatherWidget',
      'TaskPanelWidget',
      'RssWidget',
      'IframeWidget',
      'RichTextWidget',
      'CustomWidget'
    ]

    // 处理历史数据
    widgets = widgets.filter(e => supportTypes.find(type => type === e.type)).map(e => {
      // 校正未区分的类型 AppWidget AppGroupWidget
      if (e.type === 'AppWidget' && (e.apps || []).length > 1) {
        e.type = 'AppGroupWidget'
        e.minH = 2
      }
      // 校正天气组件 ID 错误
      if (e.type === 'WeatherWidget') {
        if (isNumber(e.id)) {
          e.id = genWidgetId('WEATHER_WIDGET')
        }
      }
      // 校正所有历史 APP ID 为字符串
      e.apps = e.apps?.map(app => {
        app.id = app.id + ''
        app.id = (app.id || app.id) + ''
        return app
      })
      // 历史异常数据处理 - 如果有任何异常完全重置应用组布局
      if (e.type === 'AppGroupWidget') {
        const hasException = e.apps?.find(app => {
          return !isString(app.id) ||
            !isNumber(app.x) ||
            !isNumber(app.y) ||
            app.w !== 1 ||
            app.h !== 1
        })
        if (hasException) {
          const layoutEngine = new LayoutEngine()
          e.apps = e.apps?.map(app => {
            const pos = layoutEngine.getSpacePos(1, 1, {
              cache: true,
              column: e.w
            })
            return {
              ...app,
              ...pos,
              w: 1,
              h: 1
            }
          })
          console.log('=> WidgetGroup Apps hasException', hasException, e)
        }
      }
      // 检查所有组件布局数据完整性
      if (!isNumber(e.w) || !isNumber(e.h) || !isNumber(e.x) || !isNumber(e.y)) {
        console.warn('Widget Layout Data Error: ', JSON.stringify(e))
        e = {
          ...e,
          x: 0,
          y: 0,
          w: 2,
          h: 1
        }
        console.log('Widget Layout Data Reset: ', e)
      }
      return e
    })

    // 附加默认 Widget
    if (!widgetOptions.initialized) {
      apps = state.widget.apps
      state.widget.defaultWidgets.forEach(defaultWidget => {
        if (!widgets.find(e => e.id === defaultWidget.id)) {
          widgets.push(defaultWidget)
        }
      })
    }

    // 校正 APP 格式
    apps = apps.map(app => {
      app.id = '' + app.id
      return app
    })

    dispatch('widget/syncAppWidget', {
      apps,
      widgets
    })
  },

  async initUserInfo ({ commit }) {
    const userInfo = await iUser.getCurrentUser({})
    if (!userInfo.contentVote) userInfo.contentVote = []
    commit('setUserInfo', userInfo)
    commit('setPanels', userInfo.workbenches || [])
    commit('tool/syncToolWithUser', {
      toolLike: userInfo.toolLike,
      toolCollection: userInfo.toolCollection
    })
    commit('km/syncKmFromUser', {
      contentVote: userInfo.contentVote ? userInfo.contentVote : [],
      contentCollect: userInfo.contentCollect ? userInfo.contentCollect : []
    })
  },

  async updateUserWorkbench ({ state }) {
    await iUser.updateWorkbench({
      update: state.workbenches
    })
  },

  async logout () {
    await iUser.logout()
    // await dispatch('initUserInfo')
  },

  async createPanel ({
    commit,
    dispatch,
    getters,
    state
  }, name) {
    const id = +new Date() + ''
    const isShare = getters.isShare
    commit('createPanel', {
      id: id,
      name: name
    })
    const widgets = cloneDeep(state.widget.widgets)
    await dispatch('updateUserWorkbench')
    await dispatch('switchWorkbench', id)
    if (isShare) {
      commit('widget/setWidgets', widgets)
    }
  },

  async updateWorkbench ({
    state,
    commit,
    dispatch
  }, workbench) {
    commit('setPanels', state.workbenches.map(e => {
      if (e.id === workbench.id) {
        return {
          ...e,
          name: workbench.name
        }
      }
      return e
    }))
    dispatch('updateUserWorkbench')
  },

  async deletePanel ({
    commit,
    dispatch
  }, id) {
    commit('deletePanel', id)
    await dispatch('updateUserWorkbench')
    await dispatch('switchWorkbench', 'main')
  },

  async switchWorkbench ({
    commit,
    dispatch
  }, id) {
    await dispatch('storeSave')
    commit('setCurrentPanel', { id: id })
    await dispatch('storeLoad')
  }
}

export default actions
